import { _decorator, geometry, Node, Camera, view, PhysicsSystem, EventTouch, Prefab, instantiate, v3, tween, RigidBody, MeshRenderer, Collider, Vec3, find, input, Input, Tween, KeyCode, EventKeyboard } from 'cc';
import { getCurLevelInfo, ItemNames, LoadItemPrefabByName, OpenItems } from '../../../configs/Levels';
import { ComponentEx } from '../../core/component/ComponentEx';
import Utils from '../../core/utils/Utils';
import { TileItem } from './TileItem';
import GameConst, { ITEM_TYPE } from '../../core/common/GameConst';
import WindowManager from '../../core/manager/WindowManager';
import { DrawStarLayer } from './gameui/DrawStarLayer';
import GameEvent from '../../core/event/GameEvent';
import MsgHints from '../../core/utils/MsgHints';
import Data from '../../core/manager/Data';
import WXTTUtils from '../../core/manager/WXTTUtils';
import BusyLoadingManager, { BUSY_TYPE } from '../../core/manager/BusyLoadingManager';
import { Main } from './Main';
import AudioMgr from '../../core/utils/AudioMgr';
const { Ray } = geometry;

const { ccclass, property, executeInEditMode } = _decorator;

@ccclass('GameNode')
export class GameNode extends ComponentEx {

    onEnable() {
        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
    }

    onDisable() {
        input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
        input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
    }

    collectTiles: Node[] = [];

    moveToRightPos() {
        //移动到正确位置
        this.collectTiles.map((a, i) => {
            let tileItem = a.getComponent(TileItem)
            Tween.stopAllByTarget(a)
            tween(a).to(0.3, { worldPosition: this.collectpos[i].clone(), worldScale: v3(1, 1, 1) }).call(() => {
                tileItem.auto_rotation = true;
                if (tileItem.removed) {

                    tween(a).to(0.25, { worldPosition: tileItem.removedPos }, { easing: 'backIn' }).call(async () => {

                        //最中央的播放移除特效
                        if (tileItem.playRmovedEff) {
                            //增加星星
                            let pos = this.GetNode("Main Camera").getComponent(Camera).convertToUINode(a.worldPosition, find("Canvas"));
                            let node_ani = await Utils.playSkAni("effect_hecheng", "effect", find("Canvas"), pos);
                            AudioMgr.Instance().playSFX('starCollect')
                            WXTTUtils.vibrateShort();
                            Utils.flyAnim(ITEM_TYPE.Star, node_ani, Main.Instance()._GameUI.starNode, 1, 0, (b) => {
                                if (b) {
                                    node_ani.destroy();
                                    Main.Instance()._GameUI.star++;
                                }
                            });
                        }

                        a.destroy()
                        this.moveToRightPos()
                        this.checkResult()
                    }).start()

                }
            }).start();
        })
    }
    chooseTile(tile: Node) {
        let chooseName = tile.name



        //删除点击对象从列表
        tile.getComponent(TileItem).destoryCollider()
        for (var i = 0; i < this.allTiles.length; ++i) {
            if (this.allTiles[i] == tile) {
                this.allTiles.splice(i, 1);
                break;
            }
        }

        //插入
        let bInsert = false;
        for (var i = this.collectTiles.length - 1; i >= 0; --i) {
            if (this.collectTiles[i].name == chooseName) {
                this.collectTiles.splice(i + 1, 0, tile);
                bInsert = true;
                break;
            }
        }

        if (!bInsert) {
            this.collectTiles.push(tile);
        }

        this.moveToRightPos()

        //检测要删除的
        //标记要删除的
        let tmp = this.collectTiles.filter(a => {
            return a.name == chooseName;
        })

        if (tmp.length == 3) {
            for (var i = this.collectTiles.length - 1; i >= 0; --i) {
                if (this.collectTiles[i].name == chooseName) {
                    let delNode = this.collectTiles[i];
                    delNode.getComponent(TileItem).removed = true

                    this.collectTiles.splice(i, 1);

                    delNode.getComponent(TileItem).removedPos = tmp[1].worldPosition
                    if (delNode == tmp[1])
                        delNode.getComponent(TileItem).playRmovedEff = true

                }
            }
        }

        this.checkResult()




    }
    lock=false
    checkResult() {
        if(this.lock)return
        //检测胜利和失败
        if (this.collectTiles.length >= 7) {
            this.lock=true
            if (!WindowManager.ins.isShow("OutOfBoxLayer"))
                WindowManager.ins.open("OutOfBoxLayer");
        } else if (this.collectTiles.length == 0 && this.allTiles.length == 0) {
            this.lock=true
            WindowManager.ins.open("DrawStarLayer").then((com: DrawStarLayer) => {
                com.setStar(Main.Instance()._GameUI.star);
            })
        }
    }


    private touchTileItem: TileItem = null;
    onTouchStart(event: EventTouch) {

        if (Main.Instance()._GameUI.pasue) return;
        if (Data.user.useMagnet) return;
        if (this.allTiles.length == 0) return;
        if (this.collectTiles.length >= 7) {
            return;
        }

        const p = event.getLocation();
        let camera = this.GetNode("Main Camera").getComponent(Camera);
        const r = new Ray();
        camera?.screenPointToRay(p.x, p.y, r);

        let b = PhysicsSystem.instance.raycastClosest(r, 1)
        if (b) {
            let collider = PhysicsSystem.instance.raycastClosestResult.collider;
            console.log(collider.node.name, collider.getComponent(RigidBody).group);
            let item = collider.node.parent.getComponent(TileItem);
            if (item) {
                item.enableCollider = false;
                let pos = item.node.getWorldPosition();
                pos.y += 0.3;
                item.node.setWorldPosition(pos);
                this.touchTileItem = item;
            }
        }
    }

    onTouchEnd(event: EventTouch) {

        if (Main.Instance()._GameUI.pasue) return;
        if (Data.user.useMagnet) return;
        if (!this.touchTileItem) return;
        if (this.allTiles.length == 0) return;
        if (this.collectTiles.length >= 7) {
            return;
        }

        const p = event.getLocation();
        let camera = this.GetNode("Main Camera").getComponent(Camera);
        const r = new Ray();
        camera?.screenPointToRay(p.x, p.y, r);

        let b = PhysicsSystem.instance.raycastClosest(r, 1);
        if (b) {
            let collider = PhysicsSystem.instance.raycastClosestResult.collider;

            let item = collider.node.parent.getComponent(TileItem);
            if (item && item == this.touchTileItem) {
                WXTTUtils.vibrateShort();
                this.chooseTile(item.node);
                this.touchTileItem = null;
                AudioMgr.Instance().playSFX('tap')
            }
            else {
                this.touchTileItem.enableCollider = true;
            }
        }
    }

    onTouchMove(event: EventTouch) {
        if (Main.Instance()._GameUI.pasue) return;
        if (Data.user.useMagnet) return;
        if (this.allTiles.length == 0) return;
        if (this.collectTiles.length >= 7) {
            return;
        }

        const p = event.getLocation();
        let camera = this.GetNode("Main Camera").getComponent(Camera);
        const r = new Ray();
        camera?.screenPointToRay(p.x, p.y, r);

        let b = PhysicsSystem.instance.raycastClosest(r, 1)
        if (b) {
            let collider = PhysicsSystem.instance.raycastClosestResult.collider
            let item = collider.node.parent.getComponent(TileItem);

            if (item) {
                if (this.touchTileItem && item == this.touchTileItem) {

                }
                else {
                    if (this.touchTileItem) this.touchTileItem.enableCollider = true;
                    item.enableCollider = false;
                    let pos = item.node.getWorldPosition();
                    pos.y += 0.3;
                    // console.log("切换")
                    item.node.setWorldPosition(pos);
                    this.touchTileItem = item;
                }
            }
            else {
                if (this.touchTileItem) {
                    // console.log("无目标")
                    this.touchTileItem.enableCollider = true;
                    this.touchTileItem = null;
                }
            }
        }
    }

    initWall() {
        if (!PhysicsSystem.instance) return;
        const OFFSET = 25;
        let camera = this.GetNode("Main Camera").getComponent(Camera);
        const r = new Ray();
        let size = view.getCanvasSize();
        //左边墙
        camera?.screenPointToRay(OFFSET, size.height / 2, r);
        if (PhysicsSystem.instance.raycastClosest(r)) {
            const result = PhysicsSystem.instance.raycastClosestResult;
            this.GetNode("PlaneLeft").setWorldPosition(result.hitPoint);
        }
        //右边墙
        camera?.screenPointToRay(size.width - OFFSET, size.height / 2, r);
        if (PhysicsSystem.instance.raycastClosest(r)) {
            const result = PhysicsSystem.instance.raycastClosestResult;
            this.GetNode("PlaneRight").setWorldPosition(result.hitPoint);
        }
        //上边墙
        camera?.screenPointToRay(size.width / 2, size.height - OFFSET * 4, r);
        if (PhysicsSystem.instance.raycastClosest(r)) {
            const result = PhysicsSystem.instance.raycastClosestResult;
            this.GetNode("PlaneTop").setWorldPosition(result.hitPoint);
        }

        let minx = this.GetNode("PlaneLeft").worldPosition.x;
        let maxx = this.GetNode("PlaneRight").worldPosition.x;
        let scale = (maxx - minx) / 8.461091041564941;
        this.GetNode("bottom").scale = v3(scale, scale, scale);

        //格子位置
        camera?.screenPointToRay(size.width / 2, 10, r);
        if (PhysicsSystem.instance.raycastClosest(r)) {
            const result = PhysicsSystem.instance.raycastClosestResult;
            this.GetNode("bottom").setWorldPosition(result.hitPoint);
        }

        //下边墙
        this.GetNode("PlaneDown").setWorldPosition(this.GetNode("bottom").worldPosition.add3f(0, 0, -2.5 * scale));
    }

    allTiles: Node[] = [];
    async createTiles() {
        let Margin = 0
        let minx = this.GetNode("PlaneLeft").worldPosition.x + Margin;
        let maxx = this.GetNode("PlaneRight").worldPosition.x - Margin;

        let maxz = this.GetNode("PlaneDown").worldPosition.z + Margin;
        let minz = this.GetNode("PlaneTop").worldPosition.z - Margin;

        let obj = getCurLevelInfo();
        //数量
        let tileCount = Math.floor(obj.rowCount * obj.rowCount / 3);
        // if (Data.user.lv == 1) tileCount = 2;
        // tiles = Utils.shuffle(tiles);

        let tilepools = [];

        let count1 = Math.floor(tileCount / 2);
        let count2 = tileCount - count1;

        //1从解锁池选一半
        for (let i = Data.user.openIndex - 1; i >= 0; --i) {
            tilepools.push(OpenItems[i]);
            count1--;
            if (count1 == 0) {
                break;
            }
        }
        console.log("解锁取", tileCount - (count2 + count1), "标准取", tileCount - (tileCount - (count2 + count1)))

        //2从标准池选一半
        for (let i = count2 + count1 - 1; i >= 0; --i) {
            tilepools.push(ItemNames[i]);
        }

        tilepools = Utils.shuffle(tilepools);
        Main.Instance()._GameUI.pasue = true;
        BusyLoadingManager.ins.addBusy(BUSY_TYPE.RES);
        for (let i = 0; i < tileCount; ++i) {
            let index = i;
            let ret = await LoadItemPrefabByName(tilepools[index]) as Prefab;
            if (!ret) continue;

            (ret.data.getComponentInChildren(MeshRenderer) as MeshRenderer).shadowCastingMode = MeshRenderer.ShadowCastingMode.ON;
            for (let j = 0; j < 3; ++j) {
                let lnode = this.GetNode("l" + (i * 3 + j));
                tween(this.node).delay(j * 0.03).call(() => {
                    let nomal_node: Node = instantiate(ret);
                    nomal_node.name = ret.name;
                    let tile = nomal_node.addComponent(TileItem);
                    let rigid = tile.addCollider();
                    nomal_node.scale = v3(obj.itemScale.x, obj.itemScale.y, obj.itemScale.z)

                    if (Data.user.lv == 1) {
                        nomal_node.setWorldPosition(lnode.getWorldPosition());
                        nomal_node.parent = this.node;
                        this.allTiles.push(nomal_node);
                    }
                    else {
                        let p = v3(
                            Utils.getRandomInt(minx/2, maxx/2), 
                            Utils.getRandom(12, 15),  // y轴高度在12-15之间
                            Utils.getRandomInt(minz/2, maxz/2)
                        );
                        
                        // 设置随机的初始旋转
                        nomal_node.setWorldRotationFromEuler(
                            Utils.getRandom(0, 300),
                            Utils.getRandom(0, 300), 
                            Utils.getRandom(0, 300)
                        )
                        
                        nomal_node.setWorldPosition(p);
                        nomal_node.parent = this.node;
                        
                        // 给物体一个向上的初始冲量,使其产生抛物线运动
                        rigid.applyImpulse(v3(0, 3, 0))
                        
                        this.allTiles.push(nomal_node);
                    }
                }).start()
            }

            if (i == tileCount - 1) {
                BusyLoadingManager.ins.removeBusy(BUSY_TYPE.RES);
                Main.Instance()._GameUI.pasue = false;
            }
        }

        setTimeout(() => {
            if (Data.user.useMagnet) {
                Main.Instance()._GameUI.pasue = true;
                Data.user.magnet--;
                let p = this.GetNode("magnet").worldPosition;
                this.GetNode("magnet").worldPosition = v3(-10, p.y, p.z);
                tween(this.GetNode("magnet")).to(0.5, { worldPosition: v3(0, p.y, p.z) }).call(async () => {
                    let arr = [];
                    for (var i = this.allTiles.length - 1; i >= 0; --i) {
                        let pick = false;
                        let item = this.allTiles[i];

                        let tmp: Node = arr[0];

                        if (tmp) {
                            if (tmp.name == item.name && arr.length < 3) {
                                arr.push(item);
                                pick = true;
                            }
                        }
                        else {
                            arr.push(item);
                            pick = true;
                        }

                        if (pick) {
                            let tile: TileItem = this.allTiles[i].getComponent(TileItem);
                            tile.destoryCollider();
                            this.GetNode("magnet_content").addChild(tile.node);
                            tween(tile.node).to(0.5, { worldPosition: this.GetNode(arr.length % 2 ? "m_left" : "r_left").worldPosition }).start();
                            this.allTiles.splice(i, 1);
                            console.log("删除", tile.name, this.allTiles.length)

                        }
                    }

                    Data.user.useMagnet = false;
                }).delay(1.5).to(0.5, { worldPosition: v3(10, p.y, p.z) }).call(() => {
                    this.GetNode("magnet_content").removeAllChildren();
                    Main.Instance()._GameUI.pasue = false;
                    if (Data.user.useTime && Data.user.time > 0)
                        GameEvent.Instance().dispatch(GameConst.USE_ITEM_TIME)
                }).start();
            }
            else {
                if (Data.user.useTime && Data.user.time > 0)
                    GameEvent.Instance().dispatch(GameConst.USE_ITEM_TIME)
            }
        }, 2000);
    }

    restart() {
        this.allTiles.map(a => a.destroy());
        this.allTiles = [];
        Main.Instance()._GameUI.star = 0;

        this.collectTiles.map(a => a.destroy());
        this.collectTiles = [];
        this.createTiles();
        this.lock=false
    }


    collectpos: Vec3[] = [];
    start() {
        setTimeout(() => {
            this.initWall();
            this.collectpos = [];
            this.GetNode("collectbox").children.map(a => {
                this.collectpos.push(a.worldPosition);
                a.active = false;
            })
        }, 100);

        GameEvent.Instance().register(this, GameConst.CLEAR_ALL_BOX, () => {
            console.log("清空盒子")
            this.lock=false
            setTimeout(() => {
                for (let i = 0; i < this.collectTiles.length; ++i) {
                    this.pushBask(this.collectTiles[i].name);
                }
                this.collectTiles.map(a => {
                    a.destroy();
                })
                this.collectTiles = [];
            }, 500);
        })

        //提示
        GameEvent.Instance().register(this, GameConst.USE_ITEM_HINT, () => {
            let obj = {}
            for (var i = 0; i < this.collectTiles.length; ++i) {
                let name = this.collectTiles[i].name;
                if (!obj[name]) obj[name] = 0;
                obj[name]++;
            }

            let hint_succ = false;
            let bFind = false;
            let hint_name = ""
            for (const key in obj) {
                if (obj[key] == 2) {
                    hint_name = key;
                    bFind = true;
                    break;
                }
            }
            //找到两个一样
            if (bFind) {
                console.log("找到两个一样")
                for (let i = 0; i < this.allTiles.length; ++i) {
                    if (this.allTiles[i].name == hint_name) {
                        this.chooseTile(this.allTiles[i]);
                        break;
                    }
                }
                hint_succ = true;
            }
            else {
                if (this.collectTiles.length >= 5) {
                    MsgHints.show("未找到合适物品");
                    return
                }
                else {
                    hint_name = this.collectTiles[0] ? this.collectTiles[0].name : this.allTiles[0].name;
                    let lsit = this.allTiles.filter(a => {
                        return a.name == hint_name;
                    })
                    lsit.map((a, i) => {
                        setTimeout(() => {
                            this.chooseTile(a);
                        }, 350 * i);
                    })
                    hint_succ = true;
                }
            }

            if (hint_succ) {
                Data.user.hint--;
            }
        })
    }

    //放回场景中
    async pushBask(name: string) {

        let Margin = 0;
        let maxz = this.GetNode("PlaneDown").worldPosition.z + Margin;
        let minz = this.GetNode("PlaneTop").worldPosition.z - Margin;
        let minx = this.GetNode("PlaneLeft").worldPosition.x + Margin;
        let maxx = this.GetNode("PlaneRight").worldPosition.x - Margin;

        let ret = await LoadItemPrefabByName(name) as Prefab;
        let nomal_node: Node = instantiate(ret);
        nomal_node.name = name;
        let tile = nomal_node.addComponent(TileItem);
        let rigid = tile.addCollider();
        let obj = getCurLevelInfo();
        nomal_node.scale = v3(obj.itemScale.x, obj.itemScale.y, obj.itemScale.z)
        nomal_node.parent = this.node;
        rigid.applyImpulse(v3(0, 3, 0))

        let p = v3(minx + (maxx - minx) / 2, Utils.getRandom(12, 15), minz + (maxz - minz) / 2);
        nomal_node.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300))
        nomal_node.setWorldPosition(p);
        this.allTiles.push(nomal_node);
    }

    onKeyDown(event: EventKeyboard) {
        if (Main.Instance()._GameUI.pasue) return;
        
        let force = v3(0, 0, 0);
        
        switch(event.keyCode) {
            case KeyCode.ARROW_UP:
            case KeyCode.KEY_W:
                force = v3(0, 30, 0); // 向上的力
                break;
            case KeyCode.ARROW_LEFT:
            case KeyCode.KEY_A:
                force = v3(-8, 0, 0); // 向左的力
                break;
            case KeyCode.ARROW_RIGHT:
            case KeyCode.KEY_D:
                force = v3(8, 0, 0); // 向右的力
                break;
        }

        // 只有当有力的时候才执行
        if (force.length() > 0) {
            this.allTiles.forEach(tile => {
                const tileItem = tile.getComponent(TileItem);
                if (tileItem) {
                    const rigid = tileItem.rigidBody;
                    if (rigid) {
                        rigid.applyImpulse(force);
                        WXTTUtils.vibrateShort();
                    }
                }
            });
        }
    }
}
